const util = require("util");
const ERROR_KEYWORDS = [
  'ETIMEDOUT',
  "ENOTFOUND",
  "SOCKET HANG UP",
  "ECONNRESET"
];

/**
 * @returns {()=>Promise}
 * @param {Object} func_host_obj 
 * @param {String} func_name 
 * @param {Number} max_retry 
 */
function NewFuncRetry(func_host_obj, func_name, max_retry = 5) {
  /**@type {()=>Promise} */
  let func = func_host_obj[func_name];
  if (!util.isFunction(func)) {
    let msg = `"${func_name}" attribute is not a function`
    console.log(msg);
    return () => new Promise(r => {
      r({
        ok: false,
        msg: msg
      })
    })
  };
  func = func.bind(func_host_obj);
  return (...args) => new Promise(async resolve => {
    let errors = [];
    for (let i = 1; i <= max_retry; i++) {
      if (i > 1) {
        console.log("network retry==", i, func_name, ...args)
      }
      let o_try = await func(...args);
      if (o_try.ok) {
        return resolve(o_try);
      }
      errors.push(o_try.msg)
      let flag = false;
      for (let e of ERROR_KEYWORDS) {
        if (o_try.msg && o_try.msg.toUpperCase().includes(e)) {
          flag = true;
          break;
        }
      }
      if (!flag) {
        return resolve({
          ok: false,
          msg: `${func_name}(${args.join(",")})::${errors.join("\n")}`
        })
      }
    }
    return resolve({
      ok: false,
      msg: `${func_name}(${args.join(",")})::${errors.join("\n")}`
    })
  })
}


module.exports = {
  NewFuncRetry
}